using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace ScrollViewTest.Behaviors;

public static class FloatingScrollViewerBehavior
{
    public static readonly DependencyProperty EnableFloatingScrollBarProperty =
        DependencyProperty.RegisterAttached(
            "EnableFloatingScrollBar",
            typeof(bool),
            typeof(FloatingScrollViewerBehavior),
            new PropertyMetadata(false, OnEnableFloatingScrollBarChanged));

    public static bool GetEnableFloatingScrollBar(DependencyObject obj)
    {
        return (bool)obj.GetValue(EnableFloatingScrollBarProperty);
    }
    public static void SetEnableFloatingScrollBar(DependencyObject obj, bool value)
    {
        obj.SetValue(EnableFloatingScrollBarProperty, value);
    }

    private static void OnEnableFloatingScrollBarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is ScrollViewer scrollViewer && (bool)e.NewValue)
        {
            scrollViewer.Loaded += (s, args) => InitializeScrollViewer(scrollViewer);
        }
    }

    private static void InitializeScrollViewer(ScrollViewer scrollViewer)
    {
        var template = scrollViewer.Template;
        if (template == null) return;

        var mainGrid = template.FindName("MainGrid", scrollViewer) as FrameworkElement;
        var verticalScrollBar = template.FindName("PART_VerticalScrollBar", scrollViewer) as ScrollBar;
        var horizontalScrollBar = template.FindName("PART_HorizontalScrollBar", scrollViewer) as ScrollBar;

        if (mainGrid == null) return;

        bool isOverVerticalEdge = false;
        bool isOverHorizontalEdge = false;
        bool isOverVerticalScrollBar = false;
        bool isOverHorizontalScrollBar = false;

        mainGrid.MouseMove += (s, e) =>
        {
            var position = e.GetPosition(mainGrid);
            var width = mainGrid.ActualWidth;
            var height = mainGrid.ActualHeight;

            bool wasOverVerticalEdge = isOverVerticalEdge;
            bool wasOverHorizontalEdge = isOverHorizontalEdge;

            isOverVerticalEdge = position.X >= width - 20;
            isOverHorizontalEdge = position.Y >= height - 20;

            if (verticalScrollBar != null)
            {
                if (isOverVerticalEdge && !wasOverVerticalEdge && !isOverVerticalScrollBar)
                {
                    ShowScrollBar(verticalScrollBar);
                }
                else if (!isOverVerticalEdge && wasOverVerticalEdge && !isOverVerticalScrollBar)
                {
                    HideScrollBar(verticalScrollBar);
                }
            }

            if (horizontalScrollBar != null)
            {
                if (isOverHorizontalEdge && !wasOverHorizontalEdge && !isOverHorizontalScrollBar)
                {
                    ShowScrollBar(horizontalScrollBar);
                }
                else if (!isOverHorizontalEdge && wasOverHorizontalEdge && !isOverHorizontalScrollBar)
                {
                    HideScrollBar(horizontalScrollBar);
                }
            }
        };

        mainGrid.MouseLeave += (s, e) =>
        {
            isOverVerticalEdge = false;
            isOverHorizontalEdge = false;
            if (verticalScrollBar != null && !isOverVerticalScrollBar)
            {
                HideScrollBar(verticalScrollBar);
            }
            if (horizontalScrollBar != null && !isOverHorizontalScrollBar)
            {
                HideScrollBar(horizontalScrollBar);
            }
        };

        if (verticalScrollBar != null)
        {
            verticalScrollBar.MouseEnter += (s, e) =>
            {
                isOverVerticalScrollBar = true;
                ShowScrollBar(verticalScrollBar);
            };
            verticalScrollBar.MouseLeave += (s, e) =>
            {
                isOverVerticalScrollBar = false;
                if (!isOverVerticalEdge)
                {
                    HideScrollBar(verticalScrollBar);
                }
            };
        }

        if (horizontalScrollBar != null)
        {
            horizontalScrollBar.MouseEnter += (s, e) =>
            {
                isOverHorizontalScrollBar = true;
                ShowScrollBar(horizontalScrollBar);
            };
            horizontalScrollBar.MouseLeave += (s, e) =>
            {
                isOverHorizontalScrollBar = false;
                if (!isOverHorizontalEdge)
                {
                    HideScrollBar(horizontalScrollBar);
                }
            };
        }
    }

    private static void ShowScrollBar(ScrollBar scrollBar)
    {
        var animation = new DoubleAnimation
        {
            To = 0.8,
            Duration = TimeSpan.FromMilliseconds(300),
            EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
        };
        scrollBar.BeginAnimation(UIElement.OpacityProperty, animation);
    }

    private static void HideScrollBar(ScrollBar scrollBar)
    {
        var animation = new DoubleAnimation
        {
            To = 0,
            Duration = TimeSpan.FromMilliseconds(300),
            EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
        };
        scrollBar.BeginAnimation(UIElement.OpacityProperty, animation);
    }
}
